#pragma once
#include "../dispatcher.hpp"
#include <unordered_set>
#include <mutex>

// 服务注册，发现，上线，下线通知
struct AddressHash
{
    size_t operator()(const Address &addr) const
    {
        // 1. 哈希 IP 字符串：直接复用 std::hash<std::string>（标准库实现更健壮，无需自行实现）
        std::hash<std::string> str_hash;
        size_t hash_ip = str_hash(addr.first);

        // 2. 哈希端口：将 uint16_t 端口转为 size_t，避免窄类型溢出
        size_t hash_port = static_cast<size_t>(addr.second);

        // 3. 组合哈希值：使用“移位+异或+乘法”的标准组合方式，避免抵消效应，提升分布均匀性
        // 原理：将前一个哈希值左移，为后一个哈希值腾出低位，再异或，最后乘一个质数打乱 bits
        hash_ip ^= hash_port + 0x9e3779b9 + (hash_ip << 6) + (hash_ip >> 2);

        return hash_ip;
    }
};

class Registration
{
public:
    using ptr = std::shared_ptr<Registration>;
    Registration() {}

    // 注册到despatcher 的 service_request 消息回调
    void onRequest(BaseConnection::ptr conn, ServiceRequest::ptr msg, BaseProtocol::ptr protocol)
    {
        SERVICE_OPTYPE op = msg->getOptype();
        std::string method = msg->getMethod();
        Address addr = msg->getHost();
        std::string id = msg->getId();

        // 1. 方法注册
        if (op == SERVICE_OPTYPE::REGISTER)
        {
            registered(conn, method, addr, id, protocol);
        }
        // 2. 方法发现
        else if (op == SERVICE_OPTYPE::DISCOVERY)
        {
            discoverry(conn, method, id, protocol);
        }
        // 3. 方法上线
        else if (op == SERVICE_OPTYPE::ONLINE)
        {
            registered(conn, method, addr, id, protocol);
        }
        // 4. 方法下线
        else if (op == SERVICE_OPTYPE::OFFLINE)
        {
            offLineNotify(conn, method, addr, protocol, id);
        }
        else
        {
            LOG_ERROR << "系统内部错误！";
        }
    }

    // 服务注册方连接断开
    void registerDisconnected(BaseProtocol::ptr protocol, BaseConnection::ptr conn)
    {

        std::lock_guard<std::mutex> lock(_mutex);
        Address peerAddr = conn->perrAddress();
        auto it = _connToMethods.find(peerAddr);

        if (it == _connToMethods.end())
        {
            LOG_DEBUG << "没有找到连接对应的服务注册信息";
            return;
        }

        LOG_DEBUG << "这个连接是服务注册者";

        // 先收集所有需要下线的服务，避免在遍历过程中修改容器
        std::vector<std::pair<std::string, Address>> servicesToOffline;
        for (auto &methodEntry : it->second)
        {
            const std::string &method = methodEntry.first;
            for (auto &addr : methodEntry.second)
            {
                // 检查 Address 有效性
                if (addr.first.empty() || addr.second <= 0 || addr.second > 65535)
                {
                    LOG_ERROR << "registerDisconnected: 无效 Address，跳过下线";
                    continue;
                }
                servicesToOffline.emplace_back(method, addr);
            }
        }

        // 先清除连接记录，避免后续操作中的重复处理
        _connToMethods.erase(it);

        // 然后处理所有需要下线的服务
        for (auto &service : servicesToOffline)
        {
            offline(conn, service.first, service.second, protocol);
        }

        LOG_DEBUG << "服务注册者断开, 其提供的所有服务下线";
    }

    // 服务发现方连接断开
    void discoveryDisconnected(BaseConnection::ptr conn)
    {

        std::lock_guard<std::mutex> lock(_mutex);
        Address peerAddr = conn->perrAddress();
        auto it = _connToDiscoverys.find(peerAddr);

        if (it == _connToDiscoverys.end())
        {
            LOG_DEBUG << "没有找到服务发现者的连接记录";
            return;
        }

        LOG_DEBUG << "这是服务发现者";

        // 收集所有需要处理的方法
        std::vector<std::string> methodsToProcess = it->second;

        // 先删除连接记录，避免后续操作中的重复处理
        _connToDiscoverys.erase(it);

        // 处理每个方法
        for (auto &methodName : methodsToProcess)
        {
            auto methodIt = _discoverys.find(methodName);
            if (methodIt == _discoverys.end())
            {
                continue;
            }

            // 安全地移除与当前连接相关的发现者记录
            auto &discoverers = methodIt->second;
            discoverers.erase(
                std::remove_if(discoverers.begin(), discoverers.end(),
                               [&peerAddr](const std::pair<Address, BaseConnection::ptr> &discoverer)
                               {
                                   return discoverer.first == peerAddr;
                               }),
                discoverers.end());

            // 如果该方法没有更多发现者，则完全移除
            if (discoverers.empty())
            {
                _discoverys.erase(methodIt);
                LOG_DEBUG << "方法 " << methodName << " 已无发现者，从_discoverys中移除";
            }
        }

        LOG_DEBUG << "服务发现者断开连接处理完成";
    }

    void closeCb(BaseProtocol::ptr protocol, BaseConnection::ptr conn)
    {
        LOG_DEBUG << "连接断开：" << conn->perrAddressString();
        registerDisconnected(protocol, conn);
        discoveryDisconnected(conn);
    }

private:
    // 注册和上线
    void registered(BaseConnection::ptr conn, const std::string &method, const Address &addr, const std::string &res_id, BaseProtocol::ptr protocol)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        bool flag = true;
        auto it = _methodsManager.find(method);

        if (it == _methodsManager.end())
        {
            // 这个方法首次注册
            _methodsManager.insert({method, std::unordered_set<Address, AddressHash>{{addr}}});
            _connToMethods.insert({conn->perrAddress(), std::unordered_map<std::string, std::vector<Address>>{{method, {addr}}}});

            LOG_DEBUG << "该服务首次注册成功：" << method;
        }
        else
        {
            // 此方法已经存在，看ip地址是否重复
            if (it->second.find(addr) == it->second.end())
            {
                // 不同Address
                it->second.insert(addr);

                auto connIt = _connToMethods.find(conn->perrAddress());
                if (connIt != _connToMethods.end())
                {
                    auto methodIt = connIt->second.find(method);
                    if (methodIt != connIt->second.end())
                    {
                        methodIt->second.push_back(addr);
                    }
                    else
                    {
                        connIt->second[method] = {addr};
                    }
                }
                else
                {
                    // 连接不存在，创建新条目
                    _connToMethods[conn->perrAddress()] = {{method, {addr}}};
                }

                LOG_INFO << "为服务 " << method << " 新增Address " << addr.first + ":" + std::to_string(addr.second);
            }
            else
            {
                flag = false;
                LOG_INFO << "重复的 /'方法-Address/' 注册，不予处理";
            }
        }

        // 响应
        auto res = MessageFactory::create<ServiceResponse>();
        res->setId(res_id);
        res->setType(MSG_Type::SERVICE_RES);

        // 新服务上线，对发现过此方法的连接进行通知
        if (flag)
        {
            onlineNotify(method, addr, protocol); // 客户端对通知不做响应

            res->setRcode(RCode::OK);
            if (conn && conn->connected())
            {
                try
                {
                    conn->send(protocol->serialize(res));
                    LOG_DEBUG << "服务注册/上线成功";
                }
                catch (const std::exception &e)
                {
                    LOG_ERROR << "发送注册响应失败: " << e.what();
                }
            }
        }
        else
        {
            // 注册或上线失败
            res->setRcode(RCode::REGISTER_FAILED);
            if (conn && conn->connected())
            {
                try
                {
                    conn->send(protocol->serialize(res));
                }
                catch (const std::exception &e)
                {
                    LOG_ERROR << "发送注册失败响应失败: " << e.what();
                }
            }
        }

        //     std::lock_guard<std::mutex> lock(_mutex);
        //     bool flag = true;
        //     auto it = _methodsManager.find(method);
        //     if (it == _methodsManager.end())
        //     {
        //         // 这个方法首次注册
        //         _methodsManager.insert({method, std::unordered_set<Address, AddressHash>{{addr}}});
        //         _connToMethods.insert({conn->perrAddress(), std::unordered_map<std::string, std::vector<Address>>{{method, {addr}}}});

        //         LOG_DEBUG << "该服务首次注册成功：" << method;
        //     }
        //     else
        //     {
        //         // 此方法已经存在，看ip地址是否重复
        //         if (it->second.find(addr) == it->second.end())
        //         {
        //             // 不同Address
        //             it->second.insert(addr);

        //             auto IT = _connToMethods.find(conn->perrAddress());
        //             IT->second.find(method)->second.push_back(addr);

        //             LOG_INFO << "为服务 " << method << " 新增Address" << addr.first + ":" + std::to_string(addr.second);
        //         }
        //         else
        //         {
        //             flag = false;
        //             LOG_INFO << "重复的 /'方法-Address/' 注册，不予处理";
        //         }
        //     }

        //     // 响应
        //     auto res = MessageFactory::create<ServiceResponse>();
        //     res->setId(res_id);
        //     res->setType(MSG_Type::SERVICE_RES);
        //     res->setOptype(SERVICE_OPTYPE::REGISTER);

        //     // 新服务上线，对发现过此方法的连接进行通知
        //     if (flag)
        //     {
        //         onlineNotify(method, addr, protocol); // 客户端对通知不做响应

        //         res->setRcode(RCode::OK);
        //         if (conn->connected())
        //         {
        //             conn->send(protocol->serialize(res));
        //             LOG_DEBUG << "服务注册/上线成功";
        //         }
        //     }
        //     else
        //     {
        //         // 注册或上线失败
        //         res->setRcode(RCode::REGISTER_FAILED);
        //         if (conn->connected())
        //         {
        //             conn->send(protocol->serialize(res));
        //         }
        //     }
         }

        // 服务上线通知
        void onlineNotify(const std::string &method, const Address &addr, BaseProtocol::ptr protocol)
        {
            auto it = _discoverys.find(method);
            if (it != _discoverys.end())
            {
                for (auto &e : it->second)
                {
                    if (e.second->connected())
                    {
                        auto res = MessageFactory::create<ServiceNotify>();
                        res->setType(MSG_Type::SERVICE_NOTIFY);
                        res->setId();
                        res->setOptype(SERVICE_OPTYPE::ONLINE);
                        res->setMethod(method);
                        res->setHost(addr);
                        e.second->send(protocol->serialize(res));
                        LOG_DEBUG << "服务上线通知发送成功：" << method << " 服务发现者的地址：" << e.second->perrAddressString();
                    }
                }
            }
            else
            {
                LOG_DEBUG << "当前暂时没有对此服务的发现端：" << method;
            }
    }

    void discoverry(BaseConnection::ptr conn, const std::string &method, const std::string &res_id, BaseProtocol::ptr protocol)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        // 客户端一次性发现，后续的服务变化采用通知的方式
        auto res = MessageFactory::create<ServiceResponse>();
        res->setType(MSG_Type::SERVICE_RES);
        res->setId(res_id);
        res->setMethod(method);
        res->setOptype(SERVICE_OPTYPE::DISCOVERY);

        auto it = _methodsManager.find(method);
        if (it != _methodsManager.end())
        {
            res->setHosts(std::vector<Address>(it->second.begin(), it->second.end()));
            res->setRcode(RCode::OK);
            conn->send(protocol->serialize(res));
        }
        else
        {
            res->setHosts(std::vector<Address>());
            res->setRcode(RCode::NOT_FOUND_SERVICE);
            conn->send(protocol->serialize(res));
            LOG_DEBUG << "没有发现对应的在线服务：" << method;
        }

        if (res->getRcode() == RCode::OK)
        {
            // 建立发现者映射关系
            Address peerAddr = conn->perrAddress();

            // 更新 _discoverys 映射
            auto discoveryIt = _discoverys.find(method);
            if (discoveryIt == _discoverys.end())
            {
                // 首次发现此方法
                _discoverys[method] = {{peerAddr, conn}};
                LOG_DEBUG << method << " 首次被发现，已建立连接关系进行管理";
            }
            else
            {
                // 检查是否已存在此发现者
                bool exists = false;
                for (const auto &discoverer : discoveryIt->second)
                {
                    if (discoverer.first == peerAddr)
                    {
                        exists = true;
                        break;
                    }
                }

                if (!exists)
                {
                    discoveryIt->second.emplace_back(peerAddr, conn);
                    LOG_DEBUG << "为方法 " << method << " 新增发现者";
                }
            }

            // 更新 _connToDiscoverys 映射
            auto connIt = _connToDiscoverys.find(peerAddr);
            if (connIt == _connToDiscoverys.end())
            {
                // 首次为此连接记录发现的方法
                _connToDiscoverys[peerAddr] = {method};
                LOG_DEBUG << "记录发现者连接 " << peerAddr.first << ":" << peerAddr.second
                          << " 发现的方法: " << method;
            }
            else
            {
                // 检查是否已记录此方法
                bool methodExists = false;
                for (const auto &m : connIt->second)
                {
                    if (m == method)
                    {
                        methodExists = true;
                        break;
                    }
                }

                if (!methodExists)
                {
                    connIt->second.push_back(method);
                    LOG_DEBUG << "为发现者连接 " << peerAddr.first << ":" << peerAddr.second
                              << " 新增发现的方法: " << method;
                }
            }
        }
    }

    // 服务下线通知
    void offLineNotify(BaseConnection::ptr conn, const std::string &method, const Address &addr, BaseProtocol::ptr protocol, const std::string &res_id = "")
    {
        std::lock_guard<std::mutex> lock(_mutex);
        offline(conn, method, addr, protocol, res_id);
    }

private:
    // 下线
    void offline(BaseConnection::ptr conn, const std::string &method, const Address &addr, BaseProtocol::ptr protocol, const std::string &res_id = "")
    {
        // 创建响应对象
        auto res = MessageFactory::create<ServiceResponse>();
        res->setType(MSG_Type::SERVICE_RES);
        res->setId(res_id);

        // 检查方法管理器中的服务
        auto methodIt = _methodsManager.find(method);
        if (methodIt == _methodsManager.end())
        {
            res->setRcode(RCode::NOT_FOUND_SERVICE);
            if (conn && conn->connected())
            {
                conn->send(protocol->serialize(res));
            }
            return;
        }

        // 查找特定地址
        auto addrIt = methodIt->second.find(addr);
        if (addrIt == methodIt->second.end())
        {
            res->setRcode(RCode::NOT_FOUND_SERVICE_ADDRESS);
            if (conn && conn->connected())
            {
                conn->send(protocol->serialize(res));
            }
            return;
        }

        // 从方法管理器中移除地址
        methodIt->second.erase(addrIt);

        // 如果该方法没有更多地址，则完全移除
        if (methodIt->second.empty())
        {
            _methodsManager.erase(methodIt);
            LOG_DEBUG << "服务 " << method << " 已经没有可以提供的主机";
        }

        // 发送下线通知给所有发现者
        auto discoveryIt = _discoverys.find(method);
        if (discoveryIt != _discoverys.end())
        {
            auto notify = MessageFactory::create<ServiceNotify>();
            notify->setType(MSG_Type::SERVICE_NOTIFY);
            notify->setId();
            notify->setMethod(method);
            notify->setOptype(SERVICE_OPTYPE::OFFLINE);
            notify->setHost(addr);

            std::string serializedNotify = protocol->serialize(notify);

            for (auto &discoveryEntry : discoveryIt->second)
            {
                if (discoveryEntry.second && discoveryEntry.second->connected())
                {
                    discoveryEntry.second->send(serializedNotify);
                    LOG_DEBUG << "通知 " << discoveryEntry.second->perrAddressString()
                              << " " << method << " 服务下线";
                }
            }
        }

        // 从连接方法映射中移除（如果还存在）
        auto connIt = _connToMethods.find(conn->perrAddress());
        if (connIt != _connToMethods.end())
        {
            auto methodMapIt = connIt->second.find(method);
            if (methodMapIt != connIt->second.end())
            {
                auto &addrVector = methodMapIt->second;
                addrVector.erase(std::remove(addrVector.begin(), addrVector.end(), addr),
                                 addrVector.end());

                if (addrVector.empty())
                {
                    connIt->second.erase(methodMapIt);
                }
            }

            // 如果连接没有更多方法，完全移除
            if (connIt->second.empty())
            {
                _connToMethods.erase(connIt);
            }
        }

        res->setRcode(RCode::OK);
        if (conn && conn->connected())
        {
            conn->send(protocol->serialize(res));
        }
    }

private:
    std::mutex _mutex;

    std::unordered_map<std::string, std::unordered_set<Address, AddressHash>> _methodsManager;         // 方法名到地址集合的映射, 注册/发现
    std::unordered_map<std::string, std::vector<std::pair<Address, BaseConnection::ptr>>> _discoverys; // 对发现者的映射管理，通知

    // 如果服务注册者连接断开，认为其提供的所有在线服务要下线
    std::unordered_map<Address, std::unordered_map<std::string, std::vector<Address>>, AddressHash> _connToMethods; // 比较.get()， 即指针地址

    // 如果服务发现端连接断开，对应的服务变更就不需要再重新通知
    std::unordered_map<Address, std::vector<std::string>, AddressHash> _connToDiscoverys;
};

// 构建一个服务端
class RegisterServer
{
public:
    using ptr = std::shared_ptr<RegisterServer>;
    RegisterServer() {}
    ~RegisterServer() {}

    RegisterServer(const std::string &ip, uint16_t port, const std::string &name, uint8_t io_threads = 5, bool reusePort = true)
        : _register(new Registration), _dispatcher(new Dispatcher), _netServer(new MuduoServer(ip, port, name, reusePort))
    {
        _dispatcher->setCallBack<ServiceRequest>(MSG_Type::SERVICE_REQ, std::bind(&Registration::onRequest, _register.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

        _netServer->setIoThreads(io_threads);
        _netServer->setHandlerProtocol(ProtocolFactory::create<LvProtocol>());
        _netServer->setMessageHander(std::bind(&Dispatcher::onMessage, _dispatcher.get(), std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
        _netServer->setConnCb(std::bind(&RegisterServer::onConnection, this, std::placeholders::_1));
        _netServer->setCloseCb(std::bind(&Registration::closeCb, _register.get(), _netServer->getHandlerProtocol(), std::placeholders::_1));
    }

    void start()
    {
        _netServer->start();
    }

private:
    void onConnection(BaseConnection::ptr conn)
    {
        LOG_INFO << "已连接：" << conn->perrAddressString();
    }

private:
    Registration::ptr _register;
    Dispatcher::ptr _dispatcher;
    BaseNet::ptr _netServer;
};